“我报名参加金石计划 1 期挑战——瓜分 10 万奖池,这是我的第 2 篇文章,点击查看活动详情 (opens new window)”
# 前置知识
回答这个问题之前需要具备一些 webpack-cli 的前置知识。首先我们可以检验一下对 webpack-cli 的理解情况?
- 为什么要使用 webpack-cli?
- 怎么使用呢?
- 能否判断出什么样的情况下是使用了 webpack-cli,什么情况下是直接使用 wepack 的 Node.js API?
- 使用它有什么好处?
- 是必须要用的吗?
- 。。。
如果能回答出这些问题,说明对 webpack-cli 有一定的认识,如果有不明确的可以查阅一些资料,补充这部分的知识。
官方文档介绍
命令行接口(CLI):为了更合适且方便地使用配置,可以在 webpack.config.js 中对 webpack 进行配置。CLI 中传入的任何参数会在配置文件中映射为对应的参数。
# 使用 webpack-cli
index.js
const sum = require("./sum");
console.log(sum(6 + 9));
2
sum.js
function sum(a, b) {
return a + b;
}
2
3
示例一:
命令行运行
npx webpack --entry ./index.js --output-path build
执行情况:
示例二:
webpack.config.js
const path = require("path");
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "build"),
},
mode: "none",
};
// npx webpack --entry ./index.js --output-path build
2
3
4
5
6
7
8
9
命令行运行
npx webpack
执行结果:
接下来想通过调试源码的方式,去看 webpack 与 webpack-cli 的工作流程。
# 开始调试
# 思路一
我们知道,在使用 webpack-cli 的时候,实际会去找 node_modules webpack、webpack-cli 依赖包 package.json 中定义的 bin 字段所对应的文件
bin 字段用来指定各个内部命令对应的可执行文件的位置
https://docs.npmjs.com/cli/v8/configuring-npm/package-json/#bin (opens new window)
webpack
在第 8 行打个断点
webpack-cli
第 5 行打断点
我自己在调试过程中,感觉这种方式需要不断去找去试,有时候可能就一不小心跳过关键代码了,就需要重新调试一遍。
所以就想着能不能换种思路跟代码,于是有了思路二,见下文。
# 思路二
观察控制台的日志
说明默认会自动执行计算编译时间,应该也是通过 stats 得到的,所以可以借用 Webpack 是如何计算编译时间的? (opens new window) 一文中找到的关键断点位置,打断点
重新通过 JavaScript Debug Terminal 运行命令 npx webpack,看是否能进入断点
进入断点处,发现左边调用堆栈有一堆东西,点进去看看,发现是 webpack Compiler、Compilation 等的一些执行,我们现在先不关心,因为我们要找 webpack-cli 做了些什么事情
将调用堆栈拖动到最底部,在这个关键位置(第 1789 行)打一个断点,猜测是在这里构建 compiler 对象,然后进行一系列打包,
断开调试,然后在重新输入 npx webpack 开启调试
进入断点处,观察左侧调用堆栈,出现了一些关键的调用
因为 webpack-cli 第 1789 行开始构建 compiler 对象,后续就要处理打包了,那说明之前就有 webpack-cli 处理命令行参数的相关逻辑,
这时候就可以从下往上依次看看调用情况,接下来就可以逐个打上断点,再从头调试一遍,基本就会比较清晰了,具体内容见下文。
# 调试分析
关键步骤截图并分析
首先在控制台执行 npx webpack 发生了什么
- 如果正常安装了依赖,会去执行
webpack/bin/webpack.js
- 如果正常安装了依赖,会去执行
判断 webpack-cli 是否安装,没有安装则提示安装,如果安装了,就到标记 2 的位置,执行 runCli 函数,再执行到标记 3 的位置,
require(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName]))
; 这里通过require
将webpack-cli
引入并执行进入到 node_modules\webpack-cli\bin\cli.js
中间这些过程省略,大家自行分析一下
执行到 node_modules\webpack-cli\lib\webpack-cli.js 中的 createCompiler 函数,这里面有一个关键点
let config = await this.loadConfig(options); config = await this.buildConfig(config, options);
1
2先进入到 loadConfig 函数中
- 这里判断我们在 npx webpack 后面有没有跟对应的配置参数,如果有的话,走 if 里的逻辑,如果没有的话,走 else 里的逻辑;
- 我们这个例子中,直接是 npx webpack,所以会走 else,else 内有 defaultConfigFiles,这几个就是 webpack-cli 的默认配置文件,然后会去解析里面的配置信息,得到 config
然后创建 compiler,接下来就正式开始编译工作了
进入到 node_modules\webpack\lib\webpack.js,执行 compiler.run()
在 Webpack 是如何计算编译时间的? (opens new window) 文中,是通过 Webpack 的 Node.js API 手动调用 compiler.run
# 补充知识点
# npx
npx commandname 执行流程
- 在 node_modules/.bin 目录下查找 commandname 命令是否存在,如果存在,就执行,如果不存在,到第 2 步;
- 在环境变量 $PATH 里,检查 commandname 是否存在,如果存在,就执行,如果不存在,到第 3 步;
- 将 commandname 下载到一个临时目录,使用以后再删除。
这里以项目中安装了 webpack 依赖包为例
- 控制台执行 npx webpack 命令
- 去找 node_modules/.bin 目录下去找有没有 webpack 命令,如果有,就执行它
- windows 用户
补充:这里的 node_modules/.bin/webpack.cmd 是在 npm install webpack -D 的时候生成的,该文件 "%dp0%..\webpack\bin\webpack.js" 是在 webpack package.json 的 bin 字段指定的
- 执行 webpack/bin/webpack.js 文件
# 小结
本文通过对源码的调试,对 webpack-cli 应该有一定的认识
- 可以处理命令行参数
- 可以对 webpack 的默认配置文件进行处理
也就是说我们有三种方式可以让 webpack 工作:
- 不用 webpack-cli,使用 webpack Node.js API,
const webpack = require("webpack");
const path = require("path");
function build1() {
return webpack({
entry: "./index.js",
output: {
path: path.resolve(__dirname, "build"),
},
mode: "none",
});
}
build1().run((err, stat) => {
const startTime = stat.startTime;
const endTime = stat.endTime;
console.log("构建时间", endTime - startTime);
// console.log("构建时间", stat.endTime - stat.startTime);
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 使用 webpack-cli,传入命令行参数
在控制台执行
npx webpack --entry ./index.js --output-path build --mode=none
- 使用 webpack-cli,使用配置文件进行配置
webpack.config.js
const path = require("path");
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "build"),
},
mode: "none",
};
2
3
4
5
6
7
8
# 参考
- https://nodejs.dev/en/learn/the-npx-nodejs-package-runner/ (opens new window)
- https://www.npmjs.com/package/npx (opens new window)
- https://www.ruanyifeng.com/blog/2019/02/npx.html (opens new window)
- https://webpack.js.org/api/cli (opens new window)
- https://webpack.docschina.org/api/cli/ (opens new window)
- https://docs.npmjs.com/cli/v8/configuring-npm/package-json/#bin (opens new window)